/**********************************************************************
 Copyright (C) 2009 Jaakko Vuori

 This file is part of Cimer.
 For more information, see <http://code.google.com/p/cimer/>

 Cimer is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Cimer is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Cimer.  If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************/

#include "piewidget.h"

#include <QtGui/QPainter>
#include <QtGui/QMouseEvent>
#include <math.h>
#include "keyeventhandler.h"
#include "feedbackplayer.h"

PieWidget::PieWidget(QWidget* parent) : QWidget(parent),

    m_angle(0),
    m_previousAdjustedAngle(0),
    m_text("0:00"),
    m_startSeconds(0),
    m_secondsLeft(0),
    m_mouseEventType(QEvent::None)
{
    m_keyEventHandler = new KeyEventHandler(this, this);
    m_feedbackPlayer = new FeedbackPlayer(this);

    connect(&m_tickTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
    m_tickTimer.setInterval(1000);

    // Prevents "actions" menu to be displayed on Symbian devices
    setContextMenuPolicy(Qt::NoContextMenu);
}

int PieWidget::secondsLeft() const
{
    return m_secondsLeft;
}

void PieWidget::setTime(QTime time)
{
    m_startTime = QDateTime::currentDateTime();
    m_startSeconds = time.hour() * 3600 + time.minute() * 60 + time.second();

    if (m_startSeconds >0)
    {
        m_tickTimer.start();
        handleTick();
        emit timeAdjusted(m_secondsLeft);
    }
    else // Prevent handling as normal timeout when user set time to zero
    {
        setZero();
    }
}

void PieWidget::handleNewAngle(int angle)
{
    m_startTime = QDateTime::currentDateTime();
    m_startSeconds = (angle * 3600 / 16 / 360 + 30) / 60 * 60;
    if (m_startSeconds != m_secondsLeft)
    {
        handleTick();
        if (m_mouseEventType.type() == QEvent::MouseMove)
        {
            m_feedbackPlayer->playDragEffect();
        }
    }
}

void PieWidget::prepareToRepaint(int seconds)
{
    m_angle = seconds * 16 * 360 / 3600;
    int mins = seconds / 60;
    int secs = seconds % 60;
    QString timeLeft = QString::number(mins) + ":";
    if (secs < 10) timeLeft += "0";
    timeLeft += QString::number(secs);
    m_text = timeLeft;

    repaint();
}

void PieWidget::handleTick()
{
    m_secondsLeft = m_startSeconds - m_startTime.secsTo(QDateTime::currentDateTime());
    if (m_secondsLeft < 0)
    {
        m_secondsLeft = 0;
    }

    prepareToRepaint(m_secondsLeft);

    if (m_secondsLeft == 0)
    {
        m_keyEventHandler->stop();
        if (m_tickTimer.isActive())
        {
            m_tickTimer.stop();
            emit timeElapsed();
        }
    }
}

void PieWidget::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event)

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(QBrush(QColor("red")));

    int side = width();
    if (height() < side)
    {
        side = height();
    }

    painter.save();

    painter.translate(width() / 2, height() / 2);
    painter.scale(0.99, 0.99);

    painter.drawPie(-side / 2, -side / 2, side, side, 90 * 16, -m_angle);

    painter.setBrush(QBrush(QColor("blue")));
    for (int i = 0; i < 12; ++i)
    {
        painter.drawRect(side / 2 - side / 10, -side / 100, side / 10, side / 50);
        painter.rotate(30.0);
    }

    painter.restore();

    painter.translate(0, height() / 5);

    QFont font = painter.font();
    int pointSize = side / 10;
    if (pointSize < 1)
    {
        pointSize = 1;
    }
    font.setPointSize(pointSize);
    font.setBold(true);
    painter.setFont(font);
    painter.drawText(rect(), Qt::AlignCenter, m_text);

    painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
    QLinearGradient fade(0, 0, 0, height());
    fade.setColorAt(0, QColor(0, 0, 0, 255));
    fade.setColorAt(1, QColor(0, 0, 0, 0));
    painter.fillRect(rect(), fade);

}


qreal PieWidget::degrees(qreal x, qreal y) const
{
    qreal degrees = 0;
    if (x > 0 && y >= 0)
    {
        degrees = (atan(y / x)) * (180 / 3.14);
    }
    else if (x <= 0 && y > 0)
    {
        degrees = (atan(-x / y)) * (180 / 3.14) + 90;
    }
    else if (x < 0 && y <= 0)
    {
        degrees = (atan(-y / -x)) * (180 / 3.14) + 180;
    }
    else //if (x >= 0 && y < 0)
    {
        degrees = (atan(x / -y)) * (180 / 3.14) + 270;
    }
    return degrees;
}

void PieWidget::mousePressEvent(QMouseEvent* event)
{
    m_mouseEventType = QEvent::MouseButtonPress;
    m_tickTimer.stop();

    QPointF pos = event->posF() -= QPointF(width() / 2, height() / 2);
    qreal x = pos.x();
    qreal y = -pos.y();
    m_previousAdjustedAngle = degrees(x, y);
    m_previousAdjustedAngle -= 90;
    if (m_previousAdjustedAngle < 0)
    {
        m_previousAdjustedAngle += 360;
    }

    m_feedbackPlayer->playPressEffect();
    movePointer(event);
}

void PieWidget::mouseReleaseEvent(QMouseEvent* event)
{
    Q_UNUSED(event);
    m_mouseEventType = QEvent::MouseButtonRelease;
    movePointer(event);

    if (m_secondsLeft > 0)
    {
        m_tickTimer.start();
    }
    else
    {
        m_tickTimer.stop();
    }

    if (m_secondsLeft >= 0)
    {
        emit timeAdjusted(m_secondsLeft);
    }
    m_feedbackPlayer->playReleaseEffect();
    m_mouseEventType = QEvent::None;
}

void PieWidget::mouseMoveEvent(QMouseEvent* event)
{
    m_mouseEventType = QEvent::MouseMove;
    movePointer(event);
}

void PieWidget::keyPressEvent(QKeyEvent* event)
{
    m_keyEventHandler->handleKeyPressEvent(event);
}

void PieWidget::keyReleaseEvent(QKeyEvent* event)
{
    m_keyEventHandler->handleKeyReleaseEvent(event);
}


void PieWidget::movePointer(QMouseEvent* event)
{
    QPointF pos = event->posF() -= QPointF(width() / 2, height() / 2);
    qreal x = pos.x();
    qreal y = -pos.y();

    qreal d = degrees(x, y);

    int angle = 0;
    if (d >= 0 && d < 90)
    {
        angle = (int)(90 - d) * 16;
    }
    else
    {
        angle = (int)(360 - d + 90) * 16;
    }

    d -= 90;
    if (d < 0)
    {
        d += 360;
    }

    if (fabs(d - m_previousAdjustedAngle) < 180)
    {
        handleNewAngle(angle);
        m_previousAdjustedAngle = d;
    }
    else
    {
        if (m_previousAdjustedAngle > 180)
        {
            handleNewAngle(0);
        }
        else
        {
            handleNewAngle(360 * 16);
        }
    }
}

void PieWidget::adjustTime(int minutes)
{
    int newMinutes;
    if (minutes < 0 && m_secondsLeft % 60 > 0)
    {
        newMinutes = m_secondsLeft / 60 + minutes + 1;
    }
    else
    {
        newMinutes = m_secondsLeft / 60 + minutes;
    }

    newMinutes = newMinutes < 0 ? 0 : newMinutes;
    newMinutes = newMinutes > 60 ? 60 : newMinutes;
    m_angle = newMinutes * 60 * 360 * 16 / 3600 - 30;

    if (newMinutes > 0)
    {
        handleNewAngle(m_angle);
    }
    else
    {
        // Prevent handling as normal timeout when user set time to zero
        setZero();
    }

}

void PieWidget::setZero()
{
    m_tickTimer.stop();
    m_keyEventHandler->stop();
    m_secondsLeft=0;
    prepareToRepaint(0);
    emit timeAdjusted(0);
}

void PieWidget::setPaused(bool paused)
{
    if (paused)
    {
        m_tickTimer.stop();
    }
    else
    {
        if (m_secondsLeft > 0)
        {
            m_tickTimer.start();
        }
        emit timeAdjusted(m_secondsLeft);
    }
}
